package com.bml.architect.spring;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.connection.CorrelationData;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = "classpath:spring-rabbitmq-productor.xml")
public class HighTest {

    @Autowired
    //1.注入 RabbitTemplate
    private RabbitTemplate rabbitTemplate;


    /**
     * 设置ConnectionFactory的publisher-confirms="true" 开启 确认模式。
     * <p>
     * 使用rabbitTemplate.setConfirmCallback设置回调函数。当消息发送到exchange后回调confirm方法。在方法中判断ack，如果为true，则发送成功，如果为false，则发送失败，需要处理。
     * <p>
     * 设置ConnectionFactory的publisher-returns="true" 开启 退回模式。
     * <p>
     * 使用rabbitTemplate.setReturnCallback设置退回函数，当消息从exchange路由到queue失败后，如果设置了rabbitTemplate.setMandatory(true)参数，
     * 则会将消息退回给producer。并执行回调函数returnedMessage。
     */
    @Test
    public void confirmTest() {
        rabbitTemplate.setConfirmCallback(new RabbitTemplate.ConfirmCallback() {
            /**
             *
             * @param correlationData 相关配置信息
             * @param ack   exchange交换机 是否成功收到了消息。true 成功，false代表失败
             * @param s 失败原因
             */
            @Override
            public void confirm(CorrelationData correlationData, boolean ack, String s) {
                if (ack) {
                    System.out.println("消息已到交换机spring_confirm_exchange");
                } else {
                    //接收失败
                    System.out.println("接收失败消息" + s);
                    //做一些处理，让消息再次发送。
                }
            }
        });
        for (int i = 0; i < 100; i++) {
            rabbitTemplate.convertAndSend("spring_confirm_exchange", "confirm", "message is ok!");
        }
    }

    @Test
    public void returnTest() {
        //设置交换机处理失败消息的模式   为true的时候，消息达到不了 队列时，会将消息重新返回给生产者
        rabbitTemplate.setMandatory(true);
        //return的时候，如果说发布者发布的消息，没有指定的消费者，也就是消息无法到达指定的消费者的时候会回调注册的方法
        rabbitTemplate.setReturnCallback(new RabbitTemplate.ReturnCallback() {
            /**
             *
             * @param message   消息对象
             * @param replyCode 错误码
             * @param replyText 错误信息
             * @param exchange  交换机
             * @param routingKey 路由键
             */
            @Override
            public void returnedMessage(Message message, int replyCode, String replyText, String exchange, String routingKey) {
                System.out.println("return 执行了....");

                System.out.println("message:" + message);
                System.out.println("replyCode:" + replyCode);
                System.out.println("replyText:" + replyText);
                System.out.println("exchange:" + exchange);
                System.out.println("routingKey:" + routingKey);

                //处理
            }
        });
        //进行消息发送
        rabbitTemplate.convertAndSend("spring_return_exchange", "r.1", "message return...r.1");
        //rabbitTemplate.convertAndSend("spring_return_exchange","r.2","message return...r.2");
        //rabbitTemplate.convertAndSend("spring_return_exchange","r1.1","message return...r1.1");
        //rabbitTemplate.convertAndSend("spring_return_exchange","r1.2","message return...r1.2");
        //进行睡眠操作
        try {
            Thread.sleep(5000);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }


    /**
     * TTL 全称 Time To Live（存活时间/过期时间）。
     * 当消息到达存活时间后，还没有被消费，会被自动清除。
     * RabbitMQ可以对消息设置过期时间，也可以对整个队列（Queue）设置过期时间
     * <p>
     * 设置队列过期时间使用参数：x-message-ttl，单位：ms(毫秒)，会对整个队列消息统一过期。
     * <p>
     * 设置消息过期时间使用参数：expiration。单位：ms(毫秒)，当该消息在队列头部时（消费时），会单独判断这一消息是否过期。
     * <p>
     * 如果两者都进行了设置，以时间短的为准。
     */
    @Test
    public void ttl() {
        for (int i = 0; i < 10; i++) {
            rabbitTemplate.convertAndSend("spring_ttl_exchange", "ttl.1", "ttl msg");
        }
    }


    @Test
    public void dlxTest() {
        for (int i = 0; i <5 ; i++) {
            rabbitTemplate.convertAndSend("normal_exchange", "normal.2", "dlx message ....");
        }
    }


}
